package com.qyxx.platform.inf.adapter;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 
 * 类动态加载工具类
 * 
 * Copyright:   Copyright (c)
 * Company:     ZheJiang Public Information Industry
 * @author      GaoXJ
 * @version     1.0
 *
 * Modification History:
 * Date			Author		   Version		Description
 * +------------+--------------+------------+------------------
 * 2008-11-22      GaoXJ          1.0		    Initialize Version.
 */
public class ClassLoaderUtil {

    // Log object
    private Log log = LogFactory.getLog(ClassLoaderUtil.class);
    
    private static ClassLoaderUtil clu = null;
    
    /**
     * 类与所在jar包的URL路径映射关系Map<类名, URL路径名>
     */
	private ConcurrentMap<String, String> classToURLMap = new ConcurrentHashMap<String, String>();
	
    /**
     * URL路径名与类加载器映射关系Map<URL路径名, 类加载器>
     */
	private ConcurrentMap<String, ClassLoader> urlToClassLoaderMap = new ConcurrentHashMap<String, ClassLoader>();
    
    private ClassLoaderUtil() {
    }
    
    public synchronized static ClassLoaderUtil getInstance() {
    	if(null==clu) {
    		clu = new ClassLoaderUtil();
    	}
    	return clu;
    }
    
    /**
     * Add file to CLASSPATH
     * @param s File name
     * @throws IOException  IOException
     */
    public synchronized void addFile(String s) throws IOException {
        File f = new File(s);
        addFile(f);
    }

    /**
     * Add file to CLASSPATH
     * @param f  File object
     * @throws IOException IOException
     */
    public void addFile(File f) throws IOException {
        addURL(f.toURL());
    }

    /**
     * Add URL to CLASSPATH
     * @param u URL
     * @throws IOException IOException
     */
    public void addURL(URL u) throws IOException {
        URLClassLoader ucl = new URLClassLoader(new URL[]{u}, Thread.currentThread().getContextClassLoader());
        urlToClassLoaderMap.put(u.toString(), ucl);
        /*URL urls[] = sysLoader.getURLs();
        for (int i = 0; i < urls.length; i++) {
            if (StringUtils.equalsIgnoreCase(urls[i].toString(), u.toString())) {
                if (log.isDebugEnabled()) {
                    log.debug("URL " + u + " is already in the CLASSPATH");
                }
                return;
            }
        }*/
        /*Class sysclass = URLClassLoader.class;
        try {
            Method method = sysclass.getDeclaredMethod("addURL", parameters);
            method.setAccessible(true);
            method.invoke(sysLoader, new Object[]{u});
        } catch (Throwable t) {
            t.printStackTrace();
            throw new IOException("Error, could not add URL to system classloader");
        }*/
    }
    
    /**
     * 加载class类
     * @param name
     * @return
     * @throws Exception
     */
	public synchronized Class loadClass(String name) throws Exception {
		if (StringUtils.isBlank(name))
			return null;
		String urlPath = classToURLMap.get(name);
		if(null!=urlPath) {
			//取到jar文件的url路径
			ClassLoader ucl = urlToClassLoaderMap.get(urlPath);
			if(null!=ucl) {
				Class clazz = null;
				try {
					clazz = ucl.loadClass(name);
				} catch (ClassNotFoundException e) {
					throw new Exception("在" + urlPath + "中找不到类" + name,e);
				}
				return clazz;
			} else {
				Class clazz = null;
				for(Map.Entry<String, ClassLoader> en : urlToClassLoaderMap.entrySet()) {
					ClassLoader uc = en.getValue();
					if(null!=uc) {
						try {
							clazz = uc.loadClass(name);
							classToURLMap.put(name, en.getKey());
							break;
						} catch (ClassNotFoundException e) {
							//不做处理
						}
					}
				}
				if(null==clazz) {
					//尝试用当前类加载器加载
					ClassLoader cl = Thread.currentThread().getContextClassLoader();
					try {
						clazz = cl.loadClass(name);
						urlToClassLoaderMap.put("ClassLoaderUrl", cl);
						classToURLMap.put(name, "ClassLoaderUrl");
						return clazz;
					} catch (ClassNotFoundException e) {
						//不做处理
					}
					throw new Exception("类加载器找不到类" + name);
				} else {
					return clazz;
				}
			}
		} else {
			//取不到jar文件的url路径
			Class clazz = null;
			for(Map.Entry<String, ClassLoader> en : urlToClassLoaderMap.entrySet()) {
				ClassLoader uc = en.getValue();
				if(null!=uc) {
					try {
						clazz = uc.loadClass(name);
						classToURLMap.put(name, en.getKey());
						break;
					} catch (ClassNotFoundException e) {
						//不做处理
					}
				}
			}
			if(null==clazz) {
				//尝试用当前类加载器加载
				ClassLoader cl = Thread.currentThread().getContextClassLoader();
				try {
					clazz = cl.loadClass(name);
					urlToClassLoaderMap.put("ClassLoaderUrl", cl);
					classToURLMap.put(name, "ClassLoaderUrl");
					return clazz;
				} catch (ClassNotFoundException e) {
					//不做处理
				}
				throw new Exception("类加载器找不到类" + name);
			} else {
				return clazz;
			}
		}
		/*if (StringUtils.isBlank(name))
			return null;
		Class clazz = ucl.loadClass(name);
		return clazz;*/
	}
	
	public void destroy() {
		if(null!=classToURLMap) {
			classToURLMap.clear();
		}
		if(null!=urlToClassLoaderMap) {
			urlToClassLoaderMap.clear();
		}
		log.info("所有加载接口类的自定义类加载器销毁成功");
	}
	
	/**
	 * 移除类与加载器对应关系及对应类加载器
	 * @param urlPath
	 */
	public synchronized void removeURL(String urlPath) {
		if(null!=urlPath) {
			urlToClassLoaderMap.remove(urlPath);
			List<String> tempList = new ArrayList<String>();
			for(Map.Entry<String, String> en : classToURLMap.entrySet()) {
				String url = en.getValue();
				if(urlPath.equals(url)) {
					tempList.add(en.getKey());
				}
			}
			for(String className : tempList) {
				classToURLMap.remove(className);
			}
		}
	}
    

}
